package com.baofu.paycore.manager.util;

import com.baofu.paycore.common.exception.PayCoreBizException;
import com.baofu.paycore.service.facade.enums.PayCoreErrorCode;
import com.baofu.paycore.common.exception.PayCoreServiceException;
import com.baofu.paycore.common.exception.ServiceErrorCode;
import com.baofu.paycore.dal.model.RefundStrategyModeDO;
import com.baofu.paycore.manager.model.PayBO;
import com.baofu.paycore.service.facade.enums.PayStatusEnums;
import com.baofu.paycore.service.facade.enums.PayToolRouteEnum;
import com.baofu.paycore.service.facade.enums.PayToolTypeEnum;
import com.baofu.paycore.service.facade.enums.ServiceCodeEnum;
import com.baofu.paycore.service.facade.model.refund.req.RefundReqDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.List;

/**
 * 支付退款流程校验工具类
 * <p>
 *     1、支付订单可退款校验
 * </p>
 * User: kwl Date: 2016/6/27 ProjectName: paycore Version: 5.0.0
 */
@Slf4j
public class RefundCheckUtil {

    /**
     * 支付订单可退款校验
     *
     * @param refundReqDTO    请求参数
     * @param payBO           支付原单
     */
    public static void refundCheck(RefundReqDTO refundReqDTO, PayBO payBO){

        //订单类型校验,目前仅支付支持退款
        if(!StringUtils.equals(payBO.getServiceCode(), ServiceCodeEnum.PAY.getCode())) {
            log.error("退款失败, error:{}", ServiceErrorCode.ORIG_ORDER_SERVICE_CODE_ERROR);
            throw new PayCoreServiceException(ServiceErrorCode.ORIG_ORDER_SERVICE_CODE_ERROR);
        }

        //订单状态校验
        if(!StringUtils.equals(payBO.getStatus(), PayStatusEnums.SUCCESS.getCode())){
            log.error("退款失败,error:{}", ServiceErrorCode.PAY_ORDER_NOT_SUCCESS);
            throw new PayCoreServiceException(ServiceErrorCode.PAY_ORDER_NOT_SUCCESS);
        }

        //币种校验
        if(!StringUtils.equals(refundReqDTO.getCcy(),payBO.getCcy())){
            log.error("退款失败,error:{}", ServiceErrorCode.REFUND_PAY_CCY_NOT_EQUALS);
            throw new PayCoreServiceException(ServiceErrorCode.REFUND_PAY_CCY_NOT_EQUALS);
        }

        //剩余退款金额校验
        if(payBO.getRefundAmt() == payBO.getAmt()){
            log.error("退款失败,error:{}", ServiceErrorCode.PAY_ORDER_REFUND_ALL_AMOUNT);
            throw new PayCoreServiceException(ServiceErrorCode.PAY_ORDER_REFUND_ALL_AMOUNT);
        }

        //可退款金额校验
        if(refundReqDTO.getAmt() > payBO.getAmt()-payBO.getRefundAmt()){
            log.error("退款失败,error:{}", ServiceErrorCode.REFUND_AMT_EXCEED_REFUNDABLE_AMT);
            throw new PayCoreServiceException(ServiceErrorCode.REFUND_AMT_EXCEED_REFUNDABLE_AMT);
        }
    }

    /**
     * 退款策略校验
     * <p>
     * 退款策略设计：
     * 按照正常产品退款流程，支付交易的退款，需要做一定的限制来降低系统设计的复杂程度、业务流程的合理性，
     * 以及产品可用性。所以，目前对退款策略做了一下限制：
     * 1、退款至银行卡流程：只有包含银行卡的支付的交易，才能退款到银行卡，其他非银行卡交易，不允许退至银行卡。
     * 此处进行进一步判断。
     * 2、退款到对应资金源：对于不同资金源支付的交易，退款时，支持退款到对应的资金源中，如红包、代金券、预付费卡
     * 等资金源退款，金额可以退至对应资金源。此处不做限制。
     * 3、退款至余额账户：对于所有不同资金源退款，可直接退款到余额中，此处不做限制。
     * </p>
     *
     * @param list     支付策略集合
     */
    public static void refundStrategyCheck(List<RefundStrategyModeDO> list){

        for(RefundStrategyModeDO strategyDO : list){

            if((!PayToolRouteEnum.CLEAR_WEBPAY_ROUTE.containsPayTool(strategyDO.getPayToolType())) &&
                    PayToolTypeEnum.BANK_CARD.getCode().equals(strategyDO.getRefundTargetMode())) {
                log.error("退款策略校验失败, error:{}", PayCoreErrorCode.REFUND_STRATEGY_CONFIG_ERROR);
                throw new PayCoreBizException(PayCoreErrorCode.REFUND_STRATEGY_CONFIG_ERROR);
            }
        }
    }

}
